//! # 配置管理模块
//!
//! 提供配置热更新、验证和管理功能

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;
use tokio::sync::RwLock;
use std::sync::Arc;

use crate::{AdminResult, AdminError};

/// 配置管理器
pub struct ConfigManager {
    config: Arc<RwLock<ConfigStore>>,
    watchers: Arc<RwLock<Vec<Box<dyn ConfigWatcher>>>>,
}

/// 配置存储
#[derive(Debug, Clone)]
struct ConfigStore {
    configs: HashMap<String, serde_json::Value>,
    metadata: HashMap<String, ConfigMetadata>,
}

/// 配置元数据
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigMetadata {
    pub source: String,
    pub last_updated: chrono::DateTime<chrono::Utc>,
    pub version: String,
    pub checksum: String,
}

/// 配置监听器接口
pub trait ConfigWatcher: Send + Sync {
    fn on_config_changed(&self, key: &str, old_value: &serde_json::Value, new_value: &serde_json::Value);
}

impl ConfigManager {
    /// 创建新的配置管理器
    pub fn new() -> Self {
        Self {
            config: Arc::new(RwLock::new(ConfigStore {
                configs: HashMap::new(),
                metadata: HashMap::new(),
            })),
            watchers: Arc::new(RwLock::new(Vec::new())),
        }
    }

    /// 获取配置值
    pub async fn get<T>(&self, key: &str) -> AdminResult<Option<T>>
    where
        T: for<'de> Deserialize<'de>,
    {
        let store = self.config.read().await;
        match store.configs.get(key) {
            Some(value) => {
                let parsed: T = serde_json::from_value(value.clone())
                    .map_err(|e| AdminError::config_error(&format!("配置反序列化失败: {}", e)))?;
                Ok(Some(parsed))
            }
            None => Ok(None),
        }
    }

    /// 设置配置值
    pub async fn set<T>(&self, key: &str, value: T) -> AdminResult<()>
    where
        T: Serialize,
    {
        let json_value = serde_json::to_value(value)
            .map_err(|e| AdminError::config_error(&format!("配置序列化失败: {}", e)))?;

        let old_value = {
            let mut store = self.config.write().await;
            let old = store.configs.get(key).cloned();
            store.configs.insert(key.to_string(), json_value.clone());
            store.metadata.insert(key.to_string(), ConfigMetadata {
                source: "api".to_string(),
                last_updated: chrono::Utc::now(),
                version: "1.0".to_string(),
                checksum: format!("{:x}", md5::compute(json_value.to_string().as_bytes())),
            });
            old
        };

        // 通知监听器
        self.notify_watchers(key, old_value.as_ref(), &json_value).await;

        Ok(())
    }

    /// 添加配置监听器
    pub async fn add_watcher(&self, watcher: Box<dyn ConfigWatcher>) {
        let mut watchers = self.watchers.write().await;
        watchers.push(watcher);
    }

    /// 通知所有监听器
    async fn notify_watchers(&self, key: &str, old_value: Option<&serde_json::Value>, new_value: &serde_json::Value) {
        let watchers = self.watchers.read().await;
        let default_old = serde_json::Value::Null;
        let old = old_value.unwrap_or(&default_old);
        
        for watcher in watchers.iter() {
            watcher.on_config_changed(key, old, new_value);
        }
    }

    /// 从文件加载配置
    pub async fn load_from_file<P: AsRef<Path>>(&self, path: P) -> AdminResult<()> {
        let path = path.as_ref();
        let content = tokio::fs::read_to_string(path).await
            .map_err(|e| AdminError::config_error(&format!("读取配置文件失败: {}", e)))?;

        let config: serde_json::Value = if path.extension().and_then(|s| s.to_str()) == Some("yaml") {
            serde_yaml::from_str(&content)
                .map_err(|e| AdminError::config_error(&format!("YAML解析失败: {}", e)))?
        } else {
            serde_json::from_str(&content)
                .map_err(|e| AdminError::config_error(&format!("JSON解析失败: {}", e)))?
        };

        self.merge_config(config, path.to_string_lossy().to_string()).await
    }

    /// 合并配置
    async fn merge_config(&self, config: serde_json::Value, source: String) -> AdminResult<()> {
        if let serde_json::Value::Object(map) = config {
            for (key, value) in map {
                let old_value = {
                    let mut store = self.config.write().await;
                    let old = store.configs.get(&key).cloned();
                    store.configs.insert(key.clone(), value.clone());
                    store.metadata.insert(key.clone(), ConfigMetadata {
                        source: source.clone(),
                        last_updated: chrono::Utc::now(),
                        version: "1.0".to_string(),
                        checksum: format!("{:x}", md5::compute(value.to_string().as_bytes())),
                    });
                    old
                };

                self.notify_watchers(&key, old_value.as_ref(), &value).await;
            }
        }

        Ok(())
    }

    /// 获取所有配置
    pub async fn get_all(&self) -> HashMap<String, serde_json::Value> {
        let store = self.config.read().await;
        store.configs.clone()
    }

    /// 获取配置元数据
    pub async fn get_metadata(&self, key: &str) -> Option<ConfigMetadata> {
        let store = self.config.read().await;
        store.metadata.get(key).cloned()
    }
}

impl Default for ConfigManager {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::NamedTempFile;
    use std::io::Write;

    #[tokio::test]
    async fn test_config_get_set() {
        let manager = ConfigManager::new();

        // 测试设置和获取
        manager.set("test.key", "test_value".to_string()).await.unwrap();
        let value: Option<String> = manager.get("test.key").await.unwrap();
        assert_eq!(value, Some("test_value".to_string()));

        // 测试不存在的键
        let missing: Option<String> = manager.get("missing.key").await.unwrap();
        assert_eq!(missing, None);
    }

    #[tokio::test]
    async fn test_config_from_file() {
        let manager = ConfigManager::new();

        // 创建临时配置文件
        let mut temp_file = NamedTempFile::new().unwrap();
        writeln!(temp_file, r#"{"server": {"port": 8080, "host": "localhost"}}"#).unwrap();

        // 从文件加载配置
        manager.load_from_file(temp_file.path()).await.unwrap();

        // 验证配置
        let server_config: Option<serde_json::Value> = manager.get("server").await.unwrap();
        assert!(server_config.is_some());

        let config = server_config.unwrap();
        assert_eq!(config["port"], 8080);
        assert_eq!(config["host"], "localhost");
    }
}